package mvc;

import com.yap.mvc.util.JsfUtil;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.IllegalBlockingModeException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Hashtable;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;
import javax.naming.*;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchResult;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author tadiwa
 */
@Named
@Stateless
@ViewScoped
public class ShiroLoginBean implements Serializable {

    private static final Logger log = LoggerFactory.getLogger(ShiroLoginBean.class);
    private String username;
    private String password;
    @EJB
    private com.mvc.UsersFacade ejbFacade;

    public ShiroLoginBean() {
    }

    public void doLogin() throws Exception {

        //connect the AUthentication server
        System.out.println("------------------------------------------------->>>AUTH SERVER CONN START");

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("Where is your MySQL JDBC Driver?");
            System.out.println(e.getMessage());
            return;
        }
        System.out.println("Authentication Server Connection Passed:");
        Connection connection = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/encrypto", "root", "locked");

        } catch (SQLException e) {
            System.out.println("Connection Failed!");
            System.out.println(e.getMessage());
            return;
        }
        if (connection != null) {
            System.out.println("Client machine authenticated!......................");

        } else {
            System.out.println("Failed to make connection!");
        }

        System.out.println("------------------------------------------------->>>AUTH SERVER CONN END");

        //END OF THE CHECKING CODE
        //PAC connection code
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(getUsername(), getPassword());
        Users user = ejbFacade.getUserByUsername(this.getUsername());

        if (user == null) {

            try {
                throw new Exception("User not in database");
            } catch (Exception ex) {
                JsfUtil.addErrorMessage(ex, ex.getMessage());
            }
        } else if ("ACTIVE".equalsIgnoreCase(user.getStatus())) {
            //connect to the PAC
            int default_timeout = 2000; // timeout used if timeout not provided

            String host = "10.130.0.49";
            String port = "10389";

            Socket socket = new Socket();
            InetSocketAddress endPoint = new InetSocketAddress(host,
                    Integer.parseInt(port));

            if (endPoint.isUnresolved()) {

                System.out.println(" Not able to resolve host " + endPoint);

            } else {
                try {
                    System.out.println("------------------------------------------------->>>PAC SERVER CONN START");
                    System.out.println("Testing Connection -> IP: " + host + " PORT: " + port);
                    socket.connect(endPoint, default_timeout);
                    System.out.printf("Connected:    %s  \n " + endPoint.getHostName() + "", endPoint);
                    System.out.println("\n------------------------------------------------->>>PAC SERVER CONN END");
                } catch (IOException ioe) {

                    System.out.printf("Failed to connect:    %s message: %s - %s \n", endPoint, ioe.getClass().getSimpleName(), ioe.getMessage());

                } catch (IllegalBlockingModeException ibme) {
                    System.out.printf("Failed to connect:    %s message: %s - %s \n", endPoint, ibme.getClass().getSimpleName(), ibme.getMessage());

                } catch (IllegalArgumentException iae) {

                    System.out.printf("Failed to connect:    %s message: %s - %s \n", endPoint, iae.getClass().getSimpleName(), iae.getMessage());

                } finally {
                    if (socket != null) {
                        try {
                            socket.close();
                        } catch (IOException ioex) {
                        }
                    }

                }
            }
            //END OF PAC CONN CODE
            try {
                subject.login(token);

                if (subject.hasRole("admin")) {
                    FacesContext.getCurrentInstance().getExternalContext().redirect("/yapp/faces/index.xhtml");
                    System.out.println("Client Authenticated as: " + subject.getPrincipal().toString() + "..............................");
                    System.out.println("POPULATING FROM PRIVILEGE ATTRIBUTE SERVER");
                    System.out.println("...........................................");
                    Hashtable<String, Object> env = new Hashtable<String, Object>(11);
                    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
                    env.put(Context.PROVIDER_URL, "ldap://10.130.0.49:10389/o=yap");
                    try {

                        DirContext ctx = new InitialDirContext(env);
                        Attributes answer = ctx.getAttributes("cn=" + SecurityUtils.getSubject().getPrincipal().toString() + ", ou=users");

                        // Print the answer
                        try {
                            for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
                                Attribute attr = (Attribute) ae.next();
                                System.out.println("attribute: " + attr.getID());

                                /* print each value */
                                for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out.println("value: " + e.next()))
						;
                                System.out.println("------------------------------------------------");

                            }
                            System.out.println("DECISION: " + SecurityUtils.getSubject().getPrincipal().toString() + " ROLE: Admin");
                            System.out.println("------------------------------------------------");
                        } catch (NamingException e) {
                            e.printStackTrace();
                            System.out.println(e.getMessage());
                        }
                        // printAttrs(answer);
                        // Close the context when we're done
                        ctx.close();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }

                } else if (subject.hasRole("user")) {
                    FacesContext.getCurrentInstance().getExternalContext().redirect("/yapp/faces/index.xhtml");
                    System.out.println("Client Authenticated as: " + subject.getPrincipal().toString() + "..............................");
                    System.out.println("POPULATING FROM PRIVILEGE ATTRIBUTE SERVER");
                    System.out.println("...........................................");
                    Hashtable<String, Object> env = new Hashtable<String, Object>(11);
                    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
                    env.put(Context.PROVIDER_URL, "ldap://10.130.0.49:10389/o=yap");
                    try {

                        DirContext ctx = new InitialDirContext(env);
                        Attributes answer = ctx.getAttributes("cn=" + SecurityUtils.getSubject().getPrincipal().toString() + ", ou=users");

                        // Print the answer
                        try {
                            for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) {
                                Attribute attr = (Attribute) ae.next();
                                System.out.println("attribute: " + attr.getID());

                                /* print each value */
                                for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out.println("value: " + e.next()))
						;
                                System.out.println("------------------------------------------------");

                            }
                            System.out.println("DECISION: " + SecurityUtils.getSubject().getPrincipal().toString() + " ROLE: User");
                            System.out.println("------------------------------------------------");
                        } catch (NamingException e) {
                            e.printStackTrace();
                            System.out.println(e.getMessage());
                        }
                        // printAttrs(answer);
                        // Close the context when we're done
                        ctx.close();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                }
            } catch (Exception ex) {
                facesError("Access Denied");
                log.error(ex.getMessage(), ex);
                System.out.println("Client Authenticated FAILED:.............................................");
            }

        } else {
            //Is to Change password
            try {
                subject.login(token);

                FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("oldPassword", this.getPassword());
                FacesContext.getCurrentInstance().getExternalContext().redirect("/yapp/faces/password.xhtml");
                System.out.println("------------------------------------------------");
                System.out.println(SecurityUtils.getSubject().getPrincipal().toString() + " first time instantiation");
                System.out.println("redirecting to ../password.xhtml");
                System.out.println("------------------------------------------------");
            } catch (UnknownAccountException ex) {
                facesError("Unknown Account");
                log.error(ex.getMessage(), ex);
                System.out.println(ex.getMessage());
            } catch (IncorrectCredentialsException ex) {
                facesError("Access Denied");
                log.error(ex.getMessage(), ex);
                System.out.println(ex.getMessage());
            } catch (IOException ex) {
                facesError("Unknown Error: ");
                log.error(ex.getMessage(), ex);
                System.out.println(ex.getMessage());
            } catch (AuthenticationException ex) {
                facesError("Unknown User: " + ex.getMessage());
                log.error(ex.getMessage(), ex);
                System.out.println(ex.getMessage());
            } finally {
                token.clear();
            }
        }
    }

    private void facesError(String message) {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

}
